﻿namespace Okazuki.MVVM.PrismSupport.FSharp
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Reflection;
    using Microsoft.Practices.Prism.ViewModel;
    using Okazuki.MVVM.PrismSupport.ViewModels;
    using System.ComponentModel;

    public class FsValidatableViewModelBase : FsViewModelBase, IDataErrorInfo
    {
        private ErrorsContainer<ValidationErrorViewModel> errors;

        protected FsValidatableViewModelBase()
        {
        }

        protected ErrorsContainer<ValidationErrorViewModel> Errors
        {
            get
            {
                if (this.errors == null)
                {
                    this.errors = new ErrorsContainer<ValidationErrorViewModel>(n => this.RaisePropertyChanged("HasErrors"));
                }

                return this.errors;
            }
        }

        public bool HasErrors
        {
            get
            {
                return this.Errors.HasErrors;
            }
        }

        public void ValidateObject()
        {
            foreach (var prop in this.GetType().GetProperties().Where(p => p.GetIndexParameters().Length == 0))
            {
                this.ValidateProperty(prop);
            }
        }

        protected void ValidateProperty(PropertyInfo propertyInfo)
        {
            var results = new List<ValidationResult>();
            if (!Validator.TryValidateProperty(
                    propertyInfo.GetValue(this, null),
                    new ValidationContext(this, null, null)
                    {
                        MemberName = propertyInfo.Name
                    },
                    results))
            {
                this.Errors.SetErrors(
                    propertyInfo.Name,
                    results
                        .Select(r => new ValidationErrorViewModel(propertyInfo.Name, r.ErrorMessage))
                        .ToList());
            }
            else
            {
                this.Errors.ClearErrors(propertyInfo.Name);
            }
        }

        protected void ValidateProperty(string propertyName)
        {
            this.ValidateProperty(this.GetType().GetProperty(propertyName));
        }

        protected override void RaisePropertyChanged(string propertyName)
        {
            this.ValidateProperty(propertyName);
            base.RaisePropertyChanged(propertyName);
        }


        #region IDataErrorInfo メンバー

        string IDataErrorInfo.Error
        {
            get { throw new NotSupportedException(); }
        }

        public string this[string columnName]
        {
            get 
            { 
                var e = this.Errors.GetErrors(columnName).FirstOrDefault();
                return e != null ? e.ErrorMessage : null;
            }
        }

        #endregion
    }
}
